/**
  ******************************************************************************
  * @file           : Singleton.h
  * @author         : livio[yuanfeng1897@outlook.com]
  * @brief          : Singleton
  * @attention      : None
  * @date           : 2023/3/22
  ******************************************************************************
  */

#pragma once

#include <utility>

/*
 * 以下实现都是饿汉模式
 * C++11以后静态变量的初始化都是线程安全的，
 * 使用饿汉模式最简单，省略了加锁解锁机制
 * 懒汉模式需要注意动态创建对象的线程安全性
 * 可以利用call_once实现只调用一次创建函数
 * 也可以考虑智能指针的初始化， make_shared/make_unique,
 * 需要声明智能指针为单例Class友元类，否则可能会涉及delete构造问题
 */


// Define a macro that implements the singleton pattern
#define SINGLETON(Class)        \
public:                         \
    static Class &Instance() {  \
        static Class ins;       \
        return ins;             \
    }                           \
private:                        \
    Class() = default;          \
    ~Class() = default;         \
public:                         \
    Class(Class &&) = delete;   \
    Class &operator=(Class &&) = delete;\
    Class(const Class &) = delete; \
    Class &operator=(const Class &) = delete;


// Define a template class that implements the singleton pattern
template<typename T>
class Singleton {
public:
    Singleton() = default;

    ~Singleton() = default;

    // disable copy
    Singleton(const Singleton &) = delete;

    // disable copy
    Singleton &operator=(const Singleton &) = delete;

    // disable move
    Singleton(Singleton &&) = delete;

    // disable move
    Singleton &operator=(Singleton &&) = delete;

    /**
     * Gets the singleton object
     * @param args  Constructor parameters of T
     * 通过可变参数模板传参，进行模板对象T的构造
     * 这里是模版函数，所以传参一致才认为是同一个单例对象，
     */
    template<typename ...Args>
    static T &Instance(Args &&... args) {
        static T ins{std::forward<Args>(args)...};
        return ins;
    }
};

// 直接使用模板类Singleton，
// 需要声明友元类，否则Singleton无法调用构造函数和析构函数

#define SINGLETONV2(Class)      \
    friend Singleton<Class>;    \
public:                         \
    static Class &Instance() {  \
        return Singleton<Class>::Instance(); \
    }                           \
private:                        \
    Class() = default;          \
    ~Class() = default;         \
public:                         \
    Class(Class &&) = delete;   \
    Class &operator=(Class &&) = delete;\
    Class(const Class &) = delete; \
    Class &operator=(const Class &) = delete;

